/*
 *  ME218_ISR.c
*
 *  Created by Rick Miley on 3/22/11.
 *
 */
// Note: .lss files do not display comments near goto labels ==

#include <ME218_ISR.h>
#include <avr/interrupt.h>
// ========================== RICKY ======================

//void __vector__RICKY (int, int) __attribute__((used));


ISR(__vector__RICKY,ISR_NAKED) {
	asm("nop");
	asm("nop");

	asm("nop");

	asm("nop");
	asm("reti");

}
 


// ===================== Clock 2 Interrupt ================= 
// Vector 8

ISR(TIMER2_COMPA_vect) {
	int					i,k,AUX_temp,temp;	
	unsigned char		j,LED_temp;
	int					CLUT_index, temp_index; 
	int					red_temp, green_temp, blue_temp, delay_temp;
	CLUT_FLASH_data		*temp_CT;
	LED_FLASH_data		*temp_ZT;
	CLUT_Sprite_Sizes	*qq;
	LED_Sprite_Sizes	*zz;
	register int		temp_mask, MATRIX_temp;
	
		
	
//	SCOPE_ISR_LOW (.lss)
	SCOPE_ISR_LOW
	
	_quick_ticks++;
	
	
	//==============================================================
	//==================== MIDI ===================================
	// ============================================================
	// The code runs 32k per second.
	// The MIDI bit-banged serial port has highest priority
	// We must shift the bits out at 31,250 hz
	// Each interrupt shifts one bit out.
	// Note: LSB first */
	
	// we count down from 9 to 0
	// if MIDI is in process, skip everything else
	// we don't want hiccups in other interrupt handlers
	// to throw off the timing
	
	asm volatile("clr r3");
	if(MIDI_shift>=0) {
//			goto PoorMan;
	
		if(MIDI_word & 0x0001)
			//	SCOPE_MIDI_HIGH (.lss)
			SCOPE_MIDI_HIGH
			else
			//	SCOPE_MIDI_LOW (.lss)
			SCOPE_MIDI_LOW
				
		MIDI_word>>=1;
		MIDI_shift--;		// count from 9 to 0
	}
	
//		goto int_return;
			
 	// ===================== PoorMan =================================
	// ===============================================================
	
	// Using counters inside an interrupt handler is 
	// a Poor_Man's multi-tasking
PoorMan:
	
	Poor_Man++;
	
	if(Poor_Man & 0x01)		// 1/2 time
	//	goto LED_matrix_int_handler;
		goto LED_matrix_int_handler;
	
	
	if(Poor_Man & 0x02)		// 1/4 time
	//	goto brightness_int_handler;
		goto brightness_int_handler;
	
	
	if(Poor_Man & 0x04)		// 1/8 time
	// goto GraphicSprites_int_handler;
		goto GraphicSprites_int_handler;

	if(Poor_Man & 0x08)		// 1/16 time
	// goto delay_int_handler;
		goto delay_int_handler;

	
	// fall through to the CLUT_int_handler
	
	
	// =============================================================
	// ====================== CLUT sprites =========================
	// ==============================================================
	
CLUT_int_handler:
	
	
//	SCOPE_CLUT_LOW (.lss)
	SCOPE_CLUT_LOW
	
	
	// A negative delay indicates the values are frozen
	if (ColorTable_delay[live_CLUT]>0) 		// count down the timer
			ColorTable_delay[live_CLUT]--; 
	else {
		
		// should we update the CLUT_Table entry?
		if (ColorTable_delay[live_CLUT]==0) {
			
			// how many steps in this CLUT sequence?
			// these values are constant. 
			qq=(CLUT_Sprite_Sizes*)SUPER_MAGIC_CLUT_VARIABLE;		// FIXME
			
			//qq=(CT_Sprite_Sizes*)locate_CLUT_data();
			
			qq+=live_CLUT;
			temp_index=pgm_read_word_near(&qq->the_sprite_len);
			
			
			//temp_index=CLUT_Sequence[live_CLUT].the_sprite_len;
			
			
			// have we reached the end of the sequence?
			if(ColorTable_index[live_CLUT]==temp_index) 
				// go back to beginning
				ColorTable_index[live_CLUT]=0;  
				
			
			
				// vector to actual Sprite info
			temp_CT=(CLUT_FLASH_data*)pgm_read_word_near(&qq->the_sprite_array);
			// temp_CT=CLUT_Sequence[live_CLUT].the_sprite_array;
			
			// how far have we progressed through the array 
			temp_CT+=ColorTable_index[live_CLUT];
			
			// reload with these new parameters
			delay_temp = pgm_read_word_near(&temp_CT->cs_delay);
			red_temp = pgm_read_word_near(&temp_CT->cs_red);
			green_temp = pgm_read_word_near(&temp_CT->cs_green);
			blue_temp = pgm_read_word_near(&temp_CT->cs_blue);
			
			ColorTable_delay[live_CLUT]=delay_temp;        
			ColorTable[live_CLUT].live_red_value= red_temp;
			ColorTable[live_CLUT].live_green_value= green_temp;
			ColorTable[live_CLUT].live_blue_value= blue_temp;
			
			// move to the next CLUT sprite
			ColorTable_index[live_CLUT]++;
		} // ========== ColorTable_delay[live_CLUT]==0   
	} // end of update the clut
	
	// === this runs every pass ====
	live_CLUT++;
	if (live_CLUT==numCLUTs)
		live_CLUT=0;            // take it from the top 

 
//	SCOPE_CLUT_HIGH (.lss)
	SCOPE_CLUT_HIGH
	
//	goto int_return (.lss)
	goto int_return;
	
	// ====================================================================
	// ====================== delay =======================================
	// ====================================================================

delay_int_handler:
	
	// A negative delay indicates the values are frozen
	if (LED_Table_delay>0) 		// count down the timer
		LED_Table_delay--; 
	else {
		if (LED_Table_delay==0) {
			
			// how many steps in this CLUT sequence?
			// these values are constant. 
			zz=(LED_Sprite_Sizes*)SUPER_MAGIC_LED_VARIABLE;		// FIXME
			
			//temp_index=CLUT_Sequence[live_CLUT].the_sprite_len;
			zz+=live_LED;			
			
			temp_index=pgm_read_word_near(&zz->the_LED_sprite_len);
			
			
			// have we reached the end of the sequence?
			if(LED_Table_index==temp_index) 
				// go back to beginning
				LED_Table_index=0;  
			
			// vector to actual Sprite info
			temp_ZT=(LED_FLASH_data*)pgm_read_word_near(&zz->the_LED_sprite_array);
			
			// how far have we progressed through the array 
			temp_ZT+=LED_Table_index;
			
			
			// reload with these new parameters
			LED_Table_delay = pgm_read_word_near(&temp_ZT->pgm_LED_delay);
			
			
			BRIGHT_LIGHT_0x80=pgm_read_byte_near(&temp_ZT->pgm_LED_0x80);
			BRIGHT_LIGHT_0x40=pgm_read_byte_near(&temp_ZT->pgm_LED_0x40);
			BRIGHT_LIGHT_0x20=pgm_read_byte_near(&temp_ZT->pgm_LED_0x20);
			BRIGHT_LIGHT_0x10=pgm_read_byte_near(&temp_ZT->pgm_LED_0x10);
			BRIGHT_LIGHT_0x08=pgm_read_byte_near(&temp_ZT->pgm_LED_0x08);
			BRIGHT_LIGHT_0x04=pgm_read_byte_near(&temp_ZT->pgm_LED_0x04);
			BRIGHT_LIGHT_0x02=pgm_read_byte_near(&temp_ZT->pgm_LED_0x02);
			BRIGHT_LIGHT_0x01=pgm_read_byte_near(&temp_ZT->pgm_LED_0x01);
	
					
			LED_Table_index++;
	
		} 
	} // end of update the LEDclut

	
	
	if(blinky_red_led>blinky_speed) {
		blinky_red_led=0;
		
		if(blinky_red_toggle) {
			blinky_red_toggle=0;
			
			//	SCOPE_BLINKY_LOW (.lss)
			SCOPE_BLINKY_LOW
		}
		else {
			blinky_red_toggle=1;
			
			//	SCOPE_BLINKY_HIGH (.lss)
			SCOPE_BLINKY_HIGH 
		}
	}
	
	
	blinky_red_led++;
	
	
	//	goto int_return (.lss)
	goto int_return;

	
	// =====================================================================
	// ======================== LED_matrix  ================================
	// =====================================================================
	
	
LED_matrix_int_handler:
		
	
	// Master mode and SPI enable
	
//	SPCR = 0x50;		// 0101 0000 i.e., (1 << SPE) | ( 1 << MSTR );   
	
//	AUX_temp = 0x00;	// turn AuxLEDs off most of the time
	
	if (currentBrightness++>=MAX_BRIGHTNESS) {
		currentBrightness=0;
		
//		AUX_temp=AuxLEDs;	// dim the AuxLEDs
		
		
		if (++currentCol>7) {
			currentCol=0;
			brightness_grid_index = 0;
		}
	}
	
	LED_temp=0;
	
	if(GREMLIN<BRIGHT_LIGHT_0x80)
		LED_temp|=0x80;
	if(GREMLIN<BRIGHT_LIGHT_0x40)
		LED_temp|=0x40;
	if(GREMLIN<BRIGHT_LIGHT_0x20)
		LED_temp|=0x20;
	if(GREMLIN<BRIGHT_LIGHT_0x10)
		LED_temp|=0x10;
	if(GREMLIN<BRIGHT_LIGHT_0x08)
		LED_temp|=0x08;
	if(GREMLIN<BRIGHT_LIGHT_0x04)
		LED_temp|=0x04;
	if(GREMLIN<BRIGHT_LIGHT_0x02)
		LED_temp|=0x02;
	if(GREMLIN<BRIGHT_LIGHT_0x01)
		LED_temp|=0x01;
	
	
	SPDR = LED_temp;
	
	GREMLIN++;
	if(GREMLIN>200)
		GREMLIN=0;
 

	
	// ========= free time =============
	// getting the byte from memory takes a half dozen instructions
	// The SPI is busy as we load the next value into a register
	MATRIX_temp = brightness_grid[brightness_grid_index++];
	
	
	while (!(SPSR & (1<<SPIF))) { }	// wait for SPI to shift 8 bits
		
	SPDR = 	MATRIX_temp;

	// =========== free time =============
	MATRIX_temp = brightness_grid[brightness_grid_index++];
	
	while (!(SPSR & (1<<SPIF))) { }	// wait for SPI to shift 8 bits
	
	SPDR = 	MATRIX_temp;
	
	// =========== free time =============
	MATRIX_temp = brightness_grid[brightness_grid_index++];
	
	while (!(SPSR & (1<<SPIF))) { }	// wait for SPI to shift 8 bits
	
	
	SPDR = MATRIX_temp;
		
	// =========== Unused Free time =============

	while (!(SPSR & (1<<SPIF))) { }	// wait for SPI to shift 8 bits
	
	

	// Turn display off:
	
//	PORTD |= 0xfc;	// 1111 1100
//	PORTB |= 0x11;	// 0001 0001
	
	// the CASE statement is more readable
	// variable timing
	
	switch (currentCol) {
			
		case 0:
			// bottom
			PORTD |= 0x04;		// 1111 1011 Bit PD2			
			PORTB &= 0xef;		// 1110 1111 Bit PB4
			break;
			
		case 1:
			// seventh
			PORTB |= 0x10;		// 1110 1111 Bit PB4
			PORTB &= 0xfe;		// 1111 1110 Bit PB0
			break;
			
		case 2:
			// sixth
			PORTB |= 0x01;		// 1111 1110 Bit PB0
			PORTD &= 0x7f;		// 0111 1111 Bit PD7
			break;
			
		case 3:
			// fifth
			PORTD |= 0x80;		// 0111 1111 Bit PD7
			PORTD &= 0xbf;		// 1011 1111 Bit PD6
			break;
			
		case 4:
			// fourth
			PORTD |= 0x40;		// 1011 1111 Bit PD6
			PORTD &= 0xdf;		// 1101 1111 Bit PD5
			break;
			
		case 5:
			// third 
			PORTD |= 0x20;		// 1101 1111 Bit PD5
			PORTD &= 0xef;		// 1110 1111 Bit PD4
			break;
			
		case 6:
		//	second from top
			PORTD |= 0x10;		// 1110 1111 Bit PD4
			PORTD &= 0xf7;		// 1111 0111 Bit PD3
			break;
			
		case 7:
			// top
			PORTD |= 0x08;		// 1111 0111 Bit PD3
			PORTD &= 0xfb;		// 1111 1011 Bit PD2
			break;
			
	}
	
	// ========== Pulse ==========
	// LE/DM1 input on STP16DP05
	// 20ns minimum
	
	PORTB |= 0x04;			// 0000 0100 Latch Pulse
	PORTB &= 0xfb;          //1111 1011 End Latch Pulse
	
//	SPCR = 0;				//turn off spi 

//	SCOPE_ISR_HIGH (.lss)
	SCOPE_ISR_HIGH
	
//  goto int_return	(.lss)
	goto int_return;
	
	
	// ===========================================================
	// ==================== Graphic Sprites ======================
	// ===========================================================
	
GraphicSprites_int_handler:
//	SCOPE_GRAPHIC_SPRITES_LOW (.lss)
	SCOPE_GRAPHIC_SPRITES_LOW
	
	switch (sprite_smile) {
			
			// on the first pass, clear half off screen buffer
		case (0) :
			
			/*
			 for (i=0; i<4; i++)
			 { 
			 for (j=0; j<8; j++);
			 OffScreenGameSlate[i][j]= 0;
			 }
			 */
			
			
			sprite_smile=1;
			break;
			
			// now the second pass
		case (1) :
			/*
			 for (i=4; i<8; i++)
			 { 
			 for (j=0; j<8; j++);
			 OffScreenGameSlate[i][j]= 0;
			 }
			 */
			
			sprite_smile=5;
			break;
			
			
		case (5) :
			
			sprite_smile=10;
			break;
			
			
			
		case (10) :
			for(i=0;i<8;i++) {
			 
				for (j=0; j<8; j++)
					GameSlate[i][j]=OffScreenGameSlate[i][j];
			}
			
			sprite_smile=1;
			break;
			
			
			
	}
//	SCOPE_GRAPHIC_SPRITES_HIGH (.lss)
	SCOPE_GRAPHIC_SPRITES_HIGH

//  goto int_return (.lss)
	goto int_return;
	
	// ============================================================
	// ============== Brightness Tables  =========================
	// ============================================================
	
	// ======= keep the display as fresh as a daisy ==============
		
brightness_int_handler:
		//	SCOPE_BRIGHTNESS_LOW (.lss)
		SCOPE_BRIGHTNESS_LOW
	
	switch (daisy_state) {
			
		// === 24 bytes ====
		case (0) :
			// daisy_color sequences from 0 to 7
			
			// read the raw data from from the 8x8 LED array
			temp=GameSlate[daisy_y][daisy_color];	 
			
			// this allows a Sprite to hold	a virtual CLUT id 
				// with a lookup to an actual CLUT id			
				CLUT_index = CLUT_mapper[temp];	 
			
				// fill up 24 bytes of red, green, and blue values per line
				bright_red_array[daisy_color]=ColorTable[CLUT_index].live_red_value;
				bright_green_array[daisy_color]=ColorTable[CLUT_index].live_green_value;
				bright_blue_array[daisy_color ]=ColorTable[CLUT_index].live_blue_value;
			
				daisy_color += 1;
				if (daisy_color == 8 ) {
						daisy_state = 1;			// move to red masking
						daisy_color = 0;
						bright_index = daisy_y*(15+1)*3; // each row is RGB x 15 colors
				} 
		break;
			
			// ========== red ==============	
			
		case (1) :
			
			temp_mask = 0;
			
			if(bright_red_array[0] > daisy_color)
				temp_mask |= 0x80;
			if(bright_red_array[1] > daisy_color)
				temp_mask |= 0x40;
			if(bright_red_array[2] > daisy_color)
				temp_mask |= 0x20;
			if(bright_red_array[3] > daisy_color)
				temp_mask |= 0x10;
			if(bright_red_array[4] > daisy_color)
				temp_mask |= 0x08;
			if(bright_red_array[5] > daisy_color)
				temp_mask |= 0x04;
			if(bright_red_array[6] > daisy_color)
				temp_mask |= 0x02;
			if(bright_red_array[7] > daisy_color)
				temp_mask |= 0x01;
			
			brightness_grid[bright_index]=temp_mask;
			bright_index+=3;
			daisy_color+=1;
			if (daisy_color == 16) {
				daisy_state = 2;		// move to green masking
				daisy_color = 0;
				bright_index = daisy_y*(15+1)*3+1; // each row is RGB x 15 colors
			}
		break;
			
			// ========== green ==============	
			
		case (2) :
			
			temp_mask = 0;
			
			if(bright_green_array[0] > daisy_color)
				temp_mask |= 0x80;
			if(bright_green_array[1] > daisy_color)
				temp_mask |= 0x40;
			if(bright_green_array[2] > daisy_color)
				temp_mask |= 0x20;
			if(bright_green_array[3] > daisy_color)
				temp_mask |= 0x10;
			if(bright_green_array[4] > daisy_color)
				temp_mask |= 0x08;
			if(bright_green_array[5] > daisy_color)
				temp_mask |= 0x04;
			if(bright_green_array[6] > daisy_color)
				temp_mask |= 0x02;
			if(bright_green_array[7] > daisy_color)
				temp_mask |= 0x01;
			
			brightness_grid[bright_index]=temp_mask;
			bright_index+=3;
			daisy_color+=1;
			if (daisy_color == 16) {
				daisy_state = 3;		// move to blue masking
				daisy_color = 0;
				bright_index = daisy_y*(15+1)*3+2; // each row is RGB x 15 colors
			}
		break;
			
			// ========== blue ==============	
			
		case (3) :
			
			temp_mask = 0;
			
			if(bright_blue_array[0] > daisy_color)
				temp_mask |= 0x80;
			if(bright_blue_array[1] > daisy_color)
				temp_mask |= 0x40;
			if(bright_blue_array[2] > daisy_color)
				temp_mask |= 0x20;
			if(bright_blue_array[3] > daisy_color)
				temp_mask |= 0x10;
			if(bright_blue_array[4] > daisy_color)
				temp_mask |= 0x08;
			if(bright_blue_array[5] > daisy_color)
				temp_mask |= 0x04;
			if(bright_blue_array[6] > daisy_color)
				temp_mask |= 0x02;
			if(bright_blue_array[7] > daisy_color)
				temp_mask |= 0x01;
			
			brightness_grid[bright_index]=temp_mask;
			bright_index+=3;
			daisy_color+=1;
			if (daisy_color == 16) {
				daisy_state = 0;		// go back to 24 bytes
				daisy_color = 0;
				bright_index = daisy_y*(15+1)*3; // each row is RGB x 15 colors
				
				daisy_y++;
				if (daisy_y==8) {
					daisy_y=0;
					bright_index=0;
				}
			}
		break;
			
	} // end of brightness switch
//	goto int_return;
	
	
int_return:
//	SCOPE_ISR_HIGH (.lss)
	SCOPE_ISR_HIGH
		
} // end of ISR





